// Copyright 2008 Chris Varley (http://www.contractdriven.net/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using ContractDriven.Exceptions;
using ContractDrivenTests;
using NUnit.Framework;
using ContractDriven;
using Assert = NUnit.Framework.Assert;

namespace ContractDrivenTests
{
    /// <summary>
    /// Tests for a Contract Bound Class
     /// </summary>
    [TestFixture, Description("Tests for a ContractBoundObject. As contract bound class is abstract/MustInherit it is implemented as TestContractBoundClass which implements some basic assertions)")]
    public class ContractBoundObjectTest
	{

		#region Global Setup/Teardown

		private TestContractBoundClass _context;

        [SetUp]
        public void Initialize()
        {
			//create a new 
           _context = new TestContractBoundClass("test", 100);
        }

        [TearDown]
        public void Cleanup()
        {
			_context.Dispose();
			Contract.ShutdownCheck();
        }
       
		#endregion

        #region Method Tests

        [Test]
        public void AssignInvariantTest()
        {
        	_context.MyString = "a new value";
			Assert.IsTrue(_context.MyString == "a new value");
		}

        [Test(Description="Setting the property as empty breaks an invariant assertion on TestContractBoundClass so should throw an InvariantException")]
		[ExpectedException(typeof(InvariantException))]
        public void AssignInvariantTestThrowsException()
        {
        	_context.MyString = ""; //should throw exception
		}
		
		
        [Test]
        public void PostMethodInvariantTest()
        {
        	_context.MyInt = 70;
			Assert.IsTrue(_context.MyInt == 70);
		}

        [Test(Description="Setting the property as 10 breaks an invariant assertion (should be between 50 and 100) on TestContractBoundClass so should throw an InvariantException")]
		[ExpectedException(typeof(InvariantException))]
        public void PostMethodInvariantTestThrowsException()
        {
        	_context.MyInt = 10; //should throw exception
		}
		
        [Test]
        public void RequireTest()
        {
        	_context.SetMyString_Require_StringLength_10("1234567890");
			Assert.IsTrue(_context.MyString == "1234567890");
        }
		
        [Test(Description="Passing a parameter not 10 characters long breaks a requirement on TestContractBoundClass so should throw a PreconditionException")]
		[ExpectedException(typeof(PreconditionException))]
        public void RequireTestThrowsException()
        {
        	_context.SetMyString_Require_StringLength_10("FAIL!"); //should throw exception
        }

        [Test]
        public void EnsureTest()
        {
			_context.Increment_MyInt_Ensure_DoesNotExceed_70(69);
        	Assert.IsTrue(_context.MyInt == 70);
		}
		
        [Test(Description="Passing a of 70 breaks a requirement on TestContractBoundClass that when incremented, the result should not be greater than 70. Should throw a PostconditionException")]
		[ExpectedException(typeof(PostconditionException))]
        public void EnsureTestThrowsException()
        {
			_context.Increment_MyInt_Ensure_DoesNotExceed_70(70); //should throw exception
		}


        [Test(Description="A test that ensures code that checks for a side effect runs correctly")]
        public void TrackTest()
        {
			_context.Increment_MyInt_Ensure_NoSideEffects(69);
        }

    	#endregion

    }
}
